using System;
using System.Collections.Generic;
using System.Text;

namespace GuavaData
{
    public class Union : Operator
    {
        // Relational algebra union operator

        #region Fields
        List<Operator> children;
        public List<Operator> Children
        {
            get { return children; }
            set { children = value; }
        }

        public string alias;
        #endregion Fields

        public Union(IEnumerable<Operator> operators)
        {
            children = new List<Operator>(operators);
            foreach (Operator o in operators)
            {
                o.parent = this;
            }

            // Dummy check
            if (this.children.Count <= 0)
                throw new Exception("Need to have at least one table in a union operator.");
            
            // Build list of output columns
            this.exposedColumns = new List<string>(children[0].exposedColumns);
            this.exposedDomains = new List<Domain.Domain>(children[0].exposedDomains);

            // Union-compatibility check
            int colCount = this.exposedColumns.Count;
            for (int i = 1; i < this.children.Count; i++)
            {
                // Check column count
                if (colCount != this.children[i].exposedColumns.Count)
                    throw new Exception("Number of columns between argument 0 and argument " + i.ToString() + " do not match for union operator.");

                // Check domains
                for (int j = 0; j < this.children[i].exposedDomains.Count; j++ )
                {
                    if (!(this.exposedDomains[j].Equals(this.children[i].exposedDomains[j])))
                        throw new Exception("Domains " + this.exposedDomains[j].ToString() + " and " + this.children[i].exposedDomains[j].ToString() + " do not match for union operator.");
                }
            }
        }
        public Union(IEnumerable<Operator> operators, string alias)
            : this(operators)
        {
            this.alias = alias;
        }

        public override SqlText Visit(Provider qv)
        {
            return qv.Transform(this);
        }
        public override void Visit(Transform t, Command c)
        {
            t.Expand(this, c);
        }

        public override Operator Clone()
        {
            List<Operator> lo = new List<Operator>();
            foreach (Operator o in this.Children)
                lo.Add(o.Clone());
            return new Union(lo);
        }

        public override void NotifyChange(Operator old, Operator newOp)
        {
            List<int> position = new List<int>();
            for (int i = 0; i < children.Count; i++)
                if (children[i] == old)
                {
                    position.Add(i);
                    newOp.parent = this;
                }

            foreach (int i in position)
            {
                children.RemoveAt(i);
                children.Insert(i, newOp);
            }
        }

        public override void Visit(Channel c, string table)
        {
            c.MapAliases(this, table);
        }

    }
}
